package com.pinapel.aixml.models.xml;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.pinapel.aixml.models.xml.errorHandlers.DefaultErrorReporter;
import com.pinapel.aixml.models.xml.errorHandlers.ErrorReporter;
import com.pinapel.aixml.tools.i18n.I18n;

/**
 * <p>A XML Parser capable of returning DOM representations</p>
 * @author Carlos Albaladejo
 * @since May 7, 2012
 */
public class XMLParser {
	
    /** Constants used for JAXP 1.2 */
    static final String JAXP_SCHEMA_LANGUAGE =
        "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
    static final String W3C_XML_SCHEMA =
        "http://www.w3.org/2001/XMLSchema";
    static final String JAXP_SCHEMA_SOURCE =
        "http://java.sun.com/xml/jaxp/properties/schemaSource";	
	
    /** Document Builder used to parse the XML documents **/
    private DocumentBuilder db;
    /** Document Builder Factory used to get the document builders **/
    private DocumentBuilderFactory dbf;
    /** Reporter for error handling **/
    private ErrorReporter mReporter;
    
    /**
     * Builds a new XMLParser.
     */
	public XMLParser(){
		
	}
	
	/**
	 * Parses the input XML document and obtains the DOM representation as a DomModel.
	 * @param iStream XML document to parse as an InputStream.
	 * @return DOM representation of the XML document.
	 * @throws ParserConfigurationException if problem happened while configuring the parser
	 * @throws SAXException If the ErrorHandler throws a SAXException or if 
	 * a fatal error is found and the ErrorHandler returns normally.
	 * @throws IOException If any IO errors occur.
	 */
	public DomModel parseToDom(InputStream iStream) throws ParserConfigurationException, SAXException, IOException{
		boolean ignoreWhitespace = false;
	    boolean ignoreComments = false;
	    boolean putCDATAIntoText = false;
	    boolean createEntityRefs = false;

	 	// Step 1: create a DocumentBuilderFactory and configure it
        if (dbf==null) dbf = DocumentBuilderFactory.newInstance();

        // Set namespaceAware to true to get a DOM Level 2 tree with nodes
        // containing namesapce information.  This is necessary because the
        // default value from JAXP 1.0 was defined to be false.
        dbf.setNamespaceAware(true);
        
        // Optional: set various configuration options
        dbf.setIgnoringComments(ignoreComments);
        dbf.setIgnoringElementContentWhitespace(ignoreWhitespace);
        dbf.setCoalescing(putCDATAIntoText);
        
        // The opposite of creating entity ref nodes is expanding them inline
        dbf.setExpandEntityReferences(!createEntityRefs);
        
        // Step 2: create a DocumentBuilder that satisfies the constraints
        // specified by the DocumentBuilderFactory
        
		if (db==null) db = dbf.newDocumentBuilder();				
        
        // Set an ErrorHandler before parsing
		db.setErrorHandler(mReporter);

        // Step 3: parse the input file		     
		Document doc = db.parse(iStream);
			
		DomModel dM = new DomModel(doc);  
		
		return dM;
	}
	
	/**
	 * Sets the the reporter that will handle parsing errors
	 * @param reporter ErrorReporter that will handle parsing errors
	 */
	public void setErrorReporter(ErrorReporter reporter) {
		
		if (reporter == null) {
			mReporter = new DefaultErrorReporter(I18n.getString(I18n.LG006_PARSE_FAILURE));
		}
		
		mReporter = reporter;
	}
	
}
